# 推导式（又称解析器），是 Python 独有的一种特性。使用推导式可以快速生成列表、元组、字典以及集合类型的数据，因此推导式又可细分为列表推导式、元组推导式、字
# 典推导式以及集合推导式。
#
# Python列表推导式
#
# 列表推导式可以利用 range 区间、元组、列表、字典和集合等数据类型，快速生成一个满足指定需求的列表。
#
# 列表推导式的语法格式如下：
#
#   [表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] ]
#
# 此格式中，[if 条件表达式] 不是必须的，可以使用，也可以省略。
#
# 通过列表推导式的语法格式，明显会感觉到它和 for 循环存在某些关联。其实，除去 [if 条件表达式] 部分，其余各部分的含义以及执行顺序和 for 循环是完全一样的（表
# 达式其实就是 for 循环中的循环体），即它的执行顺序如下所示：
#
#    for 迭代变量 in 可迭代对象
#         表达式
#
# 初学者可以这样认为，它只是对 for 循环语句的格式做了一下简单的变形，并用 [] 括起来而已，只不过最大的不同之处在于，列表推导式最终会将循环过程中，计算表达式得
# 到的一系列值组成一个列表。
rangeValue = range(1, 10)
derivativeList = [x + x for x in rangeValue]
# python 中的语法糖吗？
print(derivativeList)

# 还可以加以判断，满足条件的值才会执行推导式
b_list = [x * x for x in rangeValue if x % 2 == 0]
# a_list集合包含5个元素
print(b_list)

# 我的老天，还可以嵌套循环码？
oh_my_god = [(x + 1, y, z) for x in range(1, 5) for y in range(1, 5) for z in range(1, 5)]
print(oh_my_god)

# 对于包含多个循环的 for 表达式，同样可指定 if 条件。假如我们有一个需求：程序要将两个列表中的数值按“能否整除”的关系配对在一起。
# 比如 src_a 列表中包含 30，src_b 列表中包含 5，其中 30 可以整除 5，那么就将 30 和 5 配对在一起。对于上面的需求使用 for 表达
# 式来实现非常简单，
src_a = [30, 12, 66, 34, 39, 78, 36, 57, 121]
src_b = [3, 5, 7, 11]
# 只要y能整除x，就将它们配对在一起
result = [(x, y) for x in src_b for y in src_a if y % x == 0]
print(result)

#  元组推导式
#
# 元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型，快速生成一个满足指定需求的元组。
#
# 元组推导式的语法格式如下：
#
#   (表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] )
#
# 其中，用 [] 括起来的部分，可以使用，也可以省略。
#
# 通过和列表推导式做对比，你会发现，除了元组推导式是用 () 圆括号将各部分括起来，而列表推导式用的是 []，其它完全相同。不仅如此，元组推
# 导式和列表推导式的用法也完全相同。
#
# 例如，我们可以使用下面的代码生成一个包含数字 1~9 的元组
a = (x for x in range(1, 10))
print(a)

# 从上面的执行结果可以看出，使用元组推导式生成的结果并不是一个元组，而是一个生成器对象（后续会介绍），这一点和列表推导式是不同的
a = (x for x in range(1, 10))
# 很奇怪的现象，转换后的生成器对象会直接被消除
print(tuple(a))
a = (x for x in range(1, 10))
for i in a:
    print(i, end=' ')
print(tuple(a))

# 使用 __next__() 方法遍历生成器对象，也可以获得各个元素
a = (x for x in range(3))
print(a.__next__())
print(a.__next__())
print(a.__next__())
a = tuple(a)
print("转换后的元组：", a)

# 注意，无论是使用 for 循环遍历生成器对象，还是使用 __next__() 方法遍历生成器对象，遍历后原生成器对象将不复存在，这就是遍历后转换原生成器对象却得到空元组的原因。

# Python字典推导式
#
# Python 中，使用字典推导式可以借助列表、元组、字典、集合以及 range 区间，快速生成符合需求的字典。
#
# 字典推导式的语法格式如下：
#
#   {表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]}
#
# 其中，用 [] 括起来的部分，可以使用，也可以省略。
#
# 可以看到，和其它推导式的语法格式相比，唯一不同在于，字典推导式用的是大括号{}。
list_demo = ['C语言中文网', 'c.biancheng.net']
# 将列表中各字符串值为键，各字符串的长度为值，组成键值对
new_dict = {key: len(key) for key in list_demo}
print(new_dict)

old_dict = {'C语言中文网': 6, 'c.biancheng.net': 15}
new_dict = {v: k for k, v in old_dict.items()}
print(new_dict)

old_dict = {'C语言中文网': 6, 'c.biancheng.net': 15}
new_dict = {v: k for k, v in old_dict.items() if v > 10}
print(new_dict)

# Python集合推导式
#
# Python中，使用集合推导式可以借助列表、元组、字典、集合以及 range 区间，快速生成符合需求的集合。
#
# 集合推导式的语法格式和字典推导式完全相同，如下所示：
#
#   { 表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] }
#
# 其中，用 [] 括起来的部分，可以使用，也可以省略。
#
# 有读者可能会问，集合推导式和字典推导式的格式完全相同，那么给定一个类似的推导式，如何判断是哪种推导式呢？最简单直接的方式，就是根据表
# 达式进行判断，如果表达式以键值对（key：value）的形式，则证明此推导式是字典推导式；反之，则是集合推导式。
dict_demo = {'1': 1, '2': 2, '3': 3}
set_new = {x for x in dict_demo.keys()}
print(set_new)
